package com.sd.repay.utils;

import com.sd.repay.dao.BaseDao;
import com.sd.repay.jedis.impl.JedisClientSingle;
import com.sd.repay.pojo.MerchantUser;
import com.sd.repay.pojo.PlanConfig;
import com.sd.repay.service.QuickPayService;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 系统工具类
 */
public class WebUtil {

    private static final Logger log = LoggerFactory.getLogger(WebUtil.class);

    //时间转换器
    public static SimpleDateFormat simpleDateFormat;
    //换算单位（百）
    public static BigDecimal hundred = new BigDecimal("100");
    //换算单位（千）
    public static BigDecimal thousand = new BigDecimal("1000");
    //换算单位（万）
    public static BigDecimal tenThousand = new BigDecimal("10000");
    //默认字符编码
    public static final String utf8Encode = "UTF-8";
    //部署环境文件存放路径
    private static String onlineFilePath = File.separator + "opt" + File.separator + "tomcat-pro" + File.separator + "photo";

    private static BaseDao baseDao = SpringUtil.getBean("baseDaoImpl");
    private static JedisClientSingle jedisClientSingle = SpringUtil.getBean("jedisClientSingle");


    /**
     * 随机生成全球唯一UUID
     *
     * @return
     */
    public static String genUUID() {

        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }

    /**
     * 获取系统参数配置值
     *
     * @param paramKey
     * @return
     */
    public static String getSysValue(String paramKey) {
        String sql = "SELECT * FROM t_sys_config WHERE param_key = ?";
        Map<String, Object> sysConfigMap = baseDao.findFirst(sql, paramKey);
        return sysConfigMap == null ? null : StringUtil.filterNull(sysConfigMap.get("param_value"));
    }

    /**
     * 根据字典类型获取字典集合
     *
     * @param dictType
     * @return
     */
    public static List<Map<String, Object>> getSysDictList(String dictType) {
        String sql = "SELECT * FROM t_sys_dict WHERE dict_type = ? ORDER BY dict_seq ASC";
        List<Map<String, Object>> mapList = baseDao.findList(sql, dictType);
        return mapList == null ? new ArrayList<>() : mapList;
    }

    /**
     * 根据字典类型获取字典集合
     *
     * @param dictType
     * @return
     */
    public static String getSysDictValue(String dictType, String dictCode) {
        List<Map<String, Object>> mapList = getSysDictList(dictType);
        for (Map<String, Object> map : mapList) {
            if (StringUtil.filterNull(map.get("dict_code")).equals(dictCode)) {
                return StringUtil.filterNull(map.get("dict_value"));
            }
        }
        return dictCode;
    }

    /**
     * 获取下一个商户号
     *
     * @return
     */
    public static String nextMerchantNo() {
        String isOnline = getSysValue("IS_ONLINE");
        String prefix = "861";
        BigInteger defaultValue = new BigInteger("100000000000");
        if ("false".equals(isOnline)) {
            prefix = "761";
        }
        String num = nextUniqueSeqNo("t_merchant_info", "", 5);
        BigInteger big = new BigInteger(num).add(defaultValue);
        return prefix + big.toString();
    }

    /**
     * 获取下一个代理商编号
     *
     * @return
     */
    public static String nextAgentNo() {
        BigInteger defaultValue = new BigInteger("100000");
        String num = nextUniqueSeqNo("t_agent_info", "", 5);
        BigInteger big = new BigInteger(num).add(defaultValue);
        return big.toString();
    }

    /**
     * 获取下一个序列号
     *
     * @param tableName
     * @param prefix
     * @param length
     * @return
     */
    public static String nextUniqueSeqNo(String tableName, String prefix, int length) {
        Date now = new Date();

        String sql = "INSERT INTO t_unify_seq(table_name, create_time) VALUES (?, ?)";
        Long saveId = baseDao.getSaveObjId(sql, new Object[]{tableName, now});

        String seqNo = prefix + saveId.toString() + RandomUtil.getRandomNumbers(4);
        if (seqNo.length() > length) {
            seqNo = seqNo.substring(0, length);
        } else {
            String sysNano = String.valueOf(System.nanoTime());
            int addNum = (length - seqNo.length());
            if (sysNano.length() >= addNum) {
                seqNo += sysNano.substring(sysNano.length() - addNum);
            } else {
                int diffLength = addNum - sysNano.length();
                seqNo += sysNano + RandomUtil.getRandomNumbers(diffLength);
            }
        }
        return seqNo;
    }

    /**
     * 获取下一个序列号
     *
     * @param tableName
     * @param prefix
     * @return
     */
    public static String nextUniqueSeqNo(String tableName, String prefix) {

        return nextUniqueSeqNo(tableName, prefix, 20);
    }

    /**
     * 还款类型、不支持卡、允许时间删选
     *
     * @return
     */
    public static List<Map<String, Object>> getChannelByTypeAndExcludeAndTime(String repayType, Integer currHour, Object... excludeChannels) {
        String sql = "SELECT * FROM t_pay_channel WHERE channel_status = '1' AND repay_type = ? AND allow_begin_time <= ? AND allow_end_time > ? ";
        List<Object> params = new ArrayList<>();
        params.add(repayType);
        params.add(currHour);
        params.add(currHour);

        if (excludeChannels != null && excludeChannels.length > 0 && StringUtils.isNotEmpty(excludeChannels[0].toString())) {
            for (Object excludeChannel : excludeChannels) {
                sql += " AND channel_code <> ?";
                params.add(excludeChannel);
            }
        }

        sql += " ORDER BY percent ASC ";
        return baseDao.findList(sql, params.toArray());
    }

    /**
     * 根据通道名称获取通道信息
     *
     * @param acqCode
     * @return
     */
    public static Map<String, Object> getPayChannelInfo(String acqCode) {
        if (StringUtils.isNotBlank(acqCode)) {
            String sql = "SELECT * FROM t_pay_channel WHERE channel_code = ?";
            return baseDao.findFirst(sql, acqCode);
        }
        return new HashMap<>();
    }

    /**
     * 根据还款类型获取配置信息(redis缓存)
     *
     * @param repayType
     * @return
     */
    public static PlanConfig getPlanConfigByType(String repayType) {

        String sql = " SELECT * FROM t_plan_config WHERE repay_type = ? ";
        return baseDao.findFirst(PlanConfig.class, sql, repayType);
    }

    /**
     * 从redis缓存中获取阻塞的定时任务
     *
     * @return
     */
    public static Map<String, Long> getBlockTaskMap() {
        try {
            return jedisClientSingle.getMap("block_task_map");
        } catch (Exception e) {
            log.info("获取redis链接异常[{}]", e);
            return new HashMap<>();
        }
    }

    /**
     * 根据springId从集合中删除阻塞的定人任务
     *
     * @param springId
     */
    public static void removeBlockTaskBySpringId(String springId) {
        Map<String, Long> blockTaskMap = getBlockTaskMap();
        if (blockTaskMap != null && !blockTaskMap.isEmpty()) {
            blockTaskMap.remove(springId);
            jedisClientSingle.setMap("block_task_map", blockTaskMap);
        }
    }

    /**
     * 获取当前登录的商户
     *
     * @return
     */
    public static MerchantUser getCurrMerchantUser() {

        MerchantUser user = (MerchantUser) SecurityUtils.getSubject().getPrincipal();
        return user;
    }

    /**
     * 根据通道名称获取Service
     *
     * @param acqCode
     * @return
     */
    public static QuickPayService getQuickPayServiceByAcqCode(String acqCode) {

        if (StringUtil.isBlank(acqCode)) {
            return null;
        }
        acqCode = acqCode.toLowerCase();
        StringBuilder sb = new StringBuilder();
        String serviceSpringId = sb.append(Character.toLowerCase(acqCode.charAt(0))).append(acqCode.substring(1)).append("QuickPayServiceImpl").toString();

        Object serviceImplClazz = SpringUtil.getBean(serviceSpringId);

        return serviceImplClazz == null ? null : (QuickPayService) serviceImplClazz;
    }

    /**
     * 是否是Ajax请求
     *
     * @param request
     * @return
     * @author SHANHY
     * @create 2017年4月4日
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String requestedWith = request.getHeader("x-requested-with");
        if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 输出Json字符串
     *
     * @param print
     * @param response
     */
    public static void writeJson(Object print, HttpServletResponse response) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            out = response.getWriter();
            out.write(JsonUtil.objectToJson(print));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 新增日志记录
     *
     * @return
     */
    public static int saveOperateLog(String operator, String operateCode, String operateTable, String preValue,
                                     String afterValue, String operateDetail) {
        String sql = " INSERT INTO t_operate_log(operator, operate_code, operate_table, pre_value, after_value, operate_detail, operate_time, operate_from) " +
                " VALUES(?,?,?,?,?,?,?,?)";
        List<Object> params = new ArrayList<>();
        params.add(operator);
        params.add(operateCode);
        params.add(operateTable);
        params.add(preValue);
        params.add(afterValue);
        params.add(operateDetail);
        params.add(new Date());
        params.add("repay");
        return baseDao.execute(sql, params.toArray());
    }

    /**
     * 获取类的简单名称
     *
     * @param clazz
     * @return
     */
    public static String getClassSimpleName(Class clazz) {
        String className = clazz.getSimpleName();
        String big = className.substring(0, 1);
        String small = big.toLowerCase();
        String smallName = small + className.substring(1);
        return smallName;
    }

    /**
     * 获取访问IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1")) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) {
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        if (ipAddress == null) {
            ipAddress = "";
        }
        return ipAddress;
    }

    /**
     * 交易Map集合中是否有空值
     *
     * @param checkMap
     * @param excludeKeys
     * @return true：没有；false：有空值
     */
    public static boolean checkMapBlank(Map<String, String> checkMap, String[] excludeKeys) {
        if (checkMap == null || checkMap.isEmpty()) {
            return false;
        }
        String key = "", value = "";
        for (Map.Entry<String, String> entry : checkMap.entrySet()) {
            key = entry.getKey();
            value = entry.getValue();
            if (excludeKeys == null || excludeKeys.length == 0 && !ArrayUtils.contains(excludeKeys, key)) {
                if (StringUtils.isBlank(value)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 获取商户上传文件根目录
     *
     * @return
     */
    public static String getMerInfoFilePath(String merNo) {
        String isOnline = getSysValue("IS_ONLINE");
        if ("false".equals(isOnline)) {
            String webRootPath = WebUtil.class.getResource("/").getPath();
            return webRootPath + File.separator + "MerFileInfo" + (StringUtils.isBlank(merNo) ? "" : (File.separator + merNo));
        }
        return onlineFilePath + File.separator + "MerFileInfo" + (StringUtils.isBlank(merNo) ? "" : (File.separator + merNo));
    }

    /**
     * 生成随机文件名：当前年月日时分秒+五位随机数
     *
     * @return
     */
    public static String getRandomFileName(String suffix, String expand) {
        simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        String str = simpleDateFormat.format(new Date());
        String random = RandomUtil.getRandomNumbers(5);// 获取5位随机数
        return random + str + "_" + suffix + expand;// 当前时间
    }

    /**
     * 文件拷贝
     *
     * @param srcFile
     * @param destFile
     * @return
     */
    protected static void copyFile(File srcFile, File destFile) {
        int byteread = 0;
        InputStream in = null;
        OutputStream out = null;

        try {
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(destFile);
            byte[] buffer = new byte[1024];

            while ((byteread = in.read(buffer)) != -1) {
                out.write(buffer, 0, byteread);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件拷贝异常信息：" + e.getMessage());
        } finally {
            try {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error("文件拷贝异常信息：" + e.getMessage());
            }
        }
    }

    /**
     * 删除文件夹下的所有文件
     *
     * @param file
     */
    protected static void deleteFile(File file) {
        if (null != file) {
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f : files) {
                    deleteFile(f);
                }
            } else {
                file.delete();
            }
        }
    }

    /**
     * 判断文件夹是否存在，不存在就创建
     */
    public static Boolean makeFiles(String filePath) {
        File file = new File(filePath);
        if (!file.exists() && !file.isDirectory()) {
            return  true;
        } else {
            return false;
        }
    }
}
